<?php


namespace App\Repositories;


use App\Models\WarehouseOut as Model;
use App\Models\WarehouseOutProduct;
use App\Traits\CodeTrait;
use App\Traits\Logs;
use Exception;
use LTools\Repositories\RepositoryAbstract;

class WarehouseOut extends RepositoryAbstract
{

    use Logs, CodeTrait;

    /**
     * WarehouseOut constructor.
     * @param Model $model
     */
    public function __construct(Model $model)
    {
        $this->model = $model;
    }

    /**
     * @param array $attributes
     * @param int|null $perPage
     * @param array $columns
     * @param string $pageName
     * @param int|null $page
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     */
    public function paginate(array $attributes, int $perPage = null, array $columns = ['*'], $pageName = 'page', int $page = null)
    {
        return $this->model->with(['customer'])->where(
            $attributes
        )->paginate($perPage, $columns, $pageName, $page);
    }

    /**
     * @param array $attributes
     * @return bool|\Illuminate\Database\Eloquent\Model
     */
    public function create(array $attributes = [])
    {
        $productCollect = collect($attributes['products']);
        $attributes['code'] = $this->unique(4, 'WO' . date('ymd'));
        $attributes['price'] = $productCollect->sum(function ($item) {
            return $item['price'] * $item['quantity'];
        });
        $attributes['product_count'] = $productCollect->count();
        /** @var Model $model */
        $model = parent::create($attributes);
        foreach ($attributes['products'] as $product) {
            $product['product_id'] = \App\Models\Product::query()
                ->where('status', '=', 3)
                ->where('code', '=', $product['code'])
                ->where('customer_id', '=', $attributes['customer_id'])
                ->value('id');

            $model->products()->create(
                collect($product)->only(['product_id', 'attribute','expire', 'quantity', 'price', 'expiry'])->toArray()
            );
        }

        $this->recordLogs($model, '创建出库单成功');

        return $model;

    }

    /**
     * @param $id
     * @param array $columns
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model
     */
    public function edit($id, array $columns = ['*'])
    {
        return $this->model->with(['products.product'])->findOrFail($id, $columns);
    }

    /**
     * @param $id
     * @param array $columns
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model
     */
    public function show($id, array $columns = ['*'])
    {
        return $this->model->with(['customer', 'products.product', 'logs.user', 'files'])->findOrFail($id, $columns);
    }

    /**
     * @param $id
     * @param array $values
     * @return bool|\Illuminate\Database\Eloquent\Model|void
     * @throws \Throwable
     */
    public function update($id, array $values)
    {
        /** @var Model $model */
        $model = $this->model->newQuery()->where('id', '=', $id)->lockForUpdate()->first();
        if ($model->getAttribute('status') !== 0 && $model->getAttribute('status') !== 2) {
            throw new Exception('出库单状态不正确不能修改出库单');
        }

        $productCollect = collect($values['products']);
        $values['price'] = $productCollect->sum(function ($item) {
            return $item['price'] * $item['quantity'];
        });
        $values['product_count'] = $productCollect->count();
        $values['status'] = 0;

        /** @var Model $model */
        $model->fillable(array_merge($model->getFillable(), ['status']))->fill($values)->saveOrFail();
        $model->products()->delete();

        $productCollect->each(function ($product) use ($model, $values) {
            $product['product_id'] = \App\Models\Product::query()
                ->where('status', '=', 3)
                ->where('code', '=', $product['code'])
                ->where('customer_id', '=', $values['customer_id'])
                ->value('id');

            $model->products()->create(
                collect($product)->only(['product_id', 'attribute','expire', 'quantity', 'price', 'expiry'])->toArray()
            );
        });
        $this->recordLogs($model, '修改出库单成功');

        return $model;
    }

    /**
     * @param $id
     * @return Model
     * @throws \Throwable
     * @author luffyzhao@vip.126.com
     */
    public function confirm($id){
        /** @var \App\Models\WarehouseOut $model */
        $model = $this->model->newQuery()->where('id', '=', $id)->lockForUpdate()->first();
        if ($model->getAttribute('status') === 0) {
            $model->setAttribute('status', 1);
            $model->saveOrFail();

            $this->recordLogs($model, '出库单确认成功');
            return $model;
        }
        throw new Exception('出库单状态不正确不能确认出库单');
    }

    /**
     * @param $id
     * @param $remark
     * @return Model
     * @throws \Throwable
     * @author luffyzhao@vip.126.com
     */
    public function reject($id, $remark)
    {
        /** @var \App\Models\WarehouseOut $model */
        $model = $this->model->newQuery()->where('id', '=', $id)->lockForUpdate()->first();
        if ($model->getAttribute('status') === 1) {
            $model->setAttribute('status', 2);
            $model->saveOrFail();

            $this->recordLogs($model, '出库单驳回成功:' . $remark);
            return $model;
        }
        throw new Exception('出库单状态不正确不能驳回出库单');
    }

    /**
     * @param $id
     * @return Model
     * @throws \Throwable
     * @author luffyzhao@vip.126.com
     */
    public function review($id){
        /** @var \App\Models\WarehouseOut $model */
        $model = $this->model->newQuery()->where('id', '=', $id)->lockForUpdate()->first();
        if ($model->getAttribute('status') === 1) {
            $model->setAttribute('status', 3);
            $model->saveOrFail();
            /** @var BatchInventory $batchInventory */
            $batchInventory = app(BatchInventory::class);
            /** @var WarehouseOutProduct $product */
            foreach ($model->products as $product){
                try{
                    $batches = $batchInventory->productDecrement(
                        $product->getAttribute('product_id'),
                        $product->getAttribute('quantity'),
                        $product->getAttribute('attribute'),
                        $product->getAttribute('expire'),
                        $product->getAttribute('expiry')
                    );
                    foreach ($batches as $batch){
                        $model->packing()->create($batch);
                    }
                }catch (Exception $exception){
                    throw new Exception(sprintf($exception->getMessage(), $product->product->getAttribute('code')));
                }
            }

            $this->recordLogs($model, '出库单审核成功');
            return $model;
        }
        throw new Exception('出库单状态不正确不能审核出库单');
    }
}
